#ifndef FRAMEBUF_MGR_H
#define FRAMEBUF_MGR_H

#include <memory>

#include <stdlib.h>
#include <inttypes.h>

#include <etherfabric/ef_vi.h>
#include <etherfabric/vi.h>
#include <etherfabric/pd.h>
#include <etherfabric/memreg.h>
#include <etherfabric/pio.h>
#include <etherfabric/checksum.h>
#include <etherfabric/capabilities.h>

#include "common_defs.h"
#include "link_node.h"
#include "framebuf.h"

namespace usnet {

struct EFResource {
    int                 queue_id_; 
    ef_driver_handle    handle_;
    ef_pd               pd_;
    ef_vi               vi_;
    ef_memreg           memreg_;
};

class FrameBufMgr {
public:
    ~FrameBufMgr()
    {
        if (fb_tab_) {
            delete[] fb_tab_;
            fb_tab_ = nullptr;
        }
        if (mem_ptr_) {
            free(mem_ptr_);
            mem_ptr_ = nullptr;
        }
    }

    static std::shared_ptr<FrameBufMgr> MakeShared(
        EFResource* ef_res,
        const uint32_t nr_rx_fb,
        const uint32_t nr_tx_fb);

    inline uint16_t GetRecvWnd() const
    {
        // pass
        return static_cast<uint16_t>(-1u);
    }

    inline FrameBuf* GetFrameBuf(const uint32_t fb_id) const
    {
        return fb_tab_[fb_id];
    }

    inline bool RecvInit(const FrameBuf* fb)
    {
        return (ef_vi_receive_init(&ef_res_->vi_, fb->dma_addr_, fb->id_) == 0);
    }

    inline void RecvPush()
    {
        ef_vi_receive_push(&ef_res_->vi_);
    }

    EFResource*     ef_res_     { nullptr };
    const uint32_t  nr_rx_fb_   { 0 };
    const uint32_t  nr_tx_fb_   { 0 };
    const uint32_t  fb_size_    { 2048 };
    const uint32_t  memalign_   { 4096 };

    LinkNode        rx_fb_free_ { };    // posted and to be filled receving buffer list
    LinkNode        rx_fb_fill_ { };    // filled receving buffer list
    LinkNode        rx_fb_recv_ { };    // acknowledged receving buffer list
    LinkNode        rx_fb_wrng_ { };    // unuseable receiving frame buffer list
    LinkNode        tx_fb_free_ { };    // free transmitting buffer list
    LinkNode        tx_fb_fill_ { };    // data filled transmitting buffer list
    LinkNode        tx_fb_sent_ { };    // transmit and to be acknowledged buffer list
    LinkNode        tx_fb_wrng_ { };    // unuseable transmitting buffer list

    void*           mem_ptr_    { nullptr };    // frame buffer memory pointer
    FrameBuf**      fb_tab_     { nullptr };    // frame buffer array
    
private:
    FrameBufMgr(
        EFResource* ef_res,
        const uint32_t nr_rx_fb,
        const uint32_t nr_tx_fb):
        ef_res_ { ef_res },
        nr_rx_fb_ { nr_rx_fb },
        nr_tx_fb_ { nr_tx_fb }
    {
        // nothing to do
    }

    bool InitFrameBuf();
};
}
#endif